from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtTest import QTest
import sys
from functools import partial


class Singleton(object):
    def __init__(self, cls):
        self._cls = cls
        self._instance = {}

    def __call__(self):
        if self._cls not in self._instance:
            self._instance[self._cls] = self._cls()
        return self._instance[self._cls]


class riLog(QDialog):
    def __init__(self):
        super().__init__()
        self.setWindowFlags(Qt.FramelessWindowHint |
                            Qt.WindowMinimizeButtonHint)
        self.resize(700, 50)
        self.cb = QLineEdit(self)
        self.cb.setObjectName("cb")
        self.cb.resize(550, 30)
        self.cb.move(10, 10)
        self.cb.setPlaceholderText("输入标签名称")
        self.btn = QPushButton(self)
        self.btn.setText('添加页面')
        self.btn.resize(120, 40)
        self.btn.move(570, 5)
        self.btn.setObjectName("btn1")
        self.btn.clicked.connect(self.addTabs)
        Qss2 = '''
        QPushButton#btn1
            {   
                border-radius: 4px;  
                border:1px solid rgb(0,0,0);
                font-size:20px;
                background-color:#ffffff;
                }
        QComboBox#cb
            {

            }
        '''
        self.setStyleSheet(Qss2)

    def openDialog(self):

        self.setWindowTitle("Dialog")
        self.setWindowModality(Qt.ApplicationModal)
        self.exec_()

    # 自定义添加页面
    def addTabs(self):
        hide_tab = mw.tabs.tabs_text.index(mw.tabs.tabText(mw.tabs.page))
        print(mw.tabs.tabs_text.index(mw.tabs.tabText(mw.tabs.page)))

        print(len(mw.tabs.tabs_show_status))

        if mw.tabs.barWidth + 130 > mw.w:
            mw.tabs.tabs_show_status[hide_tab] = 0
            mw.tabs.r += 1

            # 显示或隐藏tab菜单
            mw.tabs.tabMenuState()

            # 根据calcutab()展示tab
            mw.tabs.updatetab()

            # 根据calcutab()隐藏tab至tabMenu
            mw.tabs.updatetabMenu()

            print('有隐藏添加')

        if len(self.cb.displayText()) == 0:
            mw.tabs.addTabs(len(mw.tabs.tabs_show_status), '空白页面' + str(len(mw.tabs.tabs_show_status)))
            print('无名添加')
            print(mw.tabs.tabs_text)

        else:
            if len(self.cb.displayText()) > 13:
                tabtext = self.cb.displayText()
                mw.tabs.addTabs(len(mw.tabs.tabs_show_status), tabtext[0:13])

            else:
                mw.tabs.addTabs(len(mw.tabs.tabs_show_status), self.cb.displayText())
            print('有名添加')

        print(mw.tabs.tabs_show_status)

        """ print(mw.tabs.tabs_show_status)
        print(self.cb.displayText()) """

        # 显示或隐藏tab菜单
        mw.tabs.tabMenuState()

        # 根据calcutab()展示tab
        mw.tabs.updatetab()

        # 根据calcutab()隐藏tab至tabMenu
        mw.tabs.updatetabMenu()

        # 跳转至新页面
        jump = mw.tabs.indexOf(mw.tabs.tabs_page[len(mw.tabs.tabs_page) - 1])
        mw.tabs.setCurrentIndex(jump)
        mw.tabs.update()
        self.reject()


# 重写QtabWidget
class TabWidget(QTabWidget):
    def __init__(self):
        super(TabWidget, self).__init__()

        self.tabbar = TabBar(self)
        self.setTabBar(self.tabbar)
        self.setTabsClosable(True)
        # self.setUsesScrollButtons(False)

        # 工具数据
        self.tabs_show_status = {}
        self.tabs_text = []
        self.tabs_page = {}
        self.tabs_width = {}
        self.tabs_menu_item = {}

        self.r = 0
        self.l = 0
        self.barWidth = 0
        self.page = -1

        # 创建标签菜单按钮
        self.btn_menu = QPushButton(self)
        self.btn_menu.hide()
        self.btn_menu_state = 0

        self.menu = QMenu(self)
        self.menu_tab = QAction('菜单', self)
        self.menu.addAction(self.menu_tab)

        # self.btn_menu = QPushButton(self)
        """ self.btn_menu.resize(30, 30)
        self.btn_menu.setText('菜单')
        self.btn_menu.move(0, 0) """

        self.btn_menu.clicked.connect(self.onClicked)
        self.tabCloseRequested.connect(self.delTabs)

    def onClicked(self):
        self.menu.exec_(QCursor.pos())

    def delTabs(self, index):

        """ self.tabs_show_status = {}
        self.tabs_text = []
        self.tabs_page = {}
        self.tabs_width = {}
        self.tabs_menu_item = {} """
        print('----------------------------------------')
        print(self.tabs_show_status)
        print(self.tabs_text)
        print(self.tabs_page)
        print(self.tabs_width)
        print(self.tabs_menu_item)
        print('----------------------------------------------')

        del_tab = mw.tabs.tabs_text.index(mw.tabs.tabText(index))
        self.barWidth -= self.tabs_width[del_tab]
        self.menu.removeAction(self.tabs_menu_item[del_tab])
        self.tabs_text.pop(del_tab)

        for i in range(0, len(self.tabs_show_status) - del_tab - 1):
            # 将被删除标签后的标签数据前移
            self.tabs_show_status[del_tab + i] = self.tabs_show_status[del_tab + i + 1]
            self.tabs_page[del_tab + i] = self.tabs_page[del_tab + i + 1]
            self.tabs_width[del_tab + i] = self.tabs_width[del_tab + i + 1]
            self.tabs_menu_item[del_tab + i] = self.tabs_menu_item[del_tab + i + 1]

        # 移除最后一个数据
        self.tabs_show_status.pop(len(self.tabs_show_status) - 1)
        self.tabs_page.pop(len(self.tabs_page) - 1)
        self.tabs_width.pop(len(self.tabs_width) - 1)
        self.tabs_menu_item.pop(len(self.tabs_menu_item) - 1)

        # 更新数据
        self.page -= 1

        # 移除页面
        self.removeTab(index)
        self.update()
        print(self.tabs_show_status)
        print(self.tabs_text)
        print(self.tabs_page)
        print(self.tabs_width)
        print(self.tabs_menu_item)
        print('-----------------------------------------------')

    # 添加页面方法
    def addTabs(self, index, text):

        self.tabs_page[index] = QWidget()
        self.addTab(self.tabs_page[index], text)
        self.tabs_text.append(text)
        self.tabs_width[index] = self.tabbar.tabSizeHint(self.page + 1).width()
        self.tabs_show_status[index] = 1

        # 删除按钮
        # self.tabbar.setTabButton(index, self.tabbar.RightSide, self.tabs_page[index])

        # 创建菜单
        self.tabs_menu_item[index] = QAction(text, self)
        self.menu.addAction(self.tabs_menu_item[index])
        self.tabs_menu_item[index].triggered.connect(partial(self.menuJump, index))
        self.btn_menu.resize(25, 30)

        # 窗口宽度
        self.barWidth += self.tabs_width[index]

        self.page += 1

        # 最右与最左tab的宽度
        self.tab_Rwidth = self.tabbar.tabSizeHint(self.page).width()
        self.tab_Lwidth = self.tabbar.tabSizeHint(0).width()

        self.tabMenuState()
        print(self.tabs_width)
        print(self.tabs_show_status)

    def update(self):
        i = 0
        while self.barWidth != mw.w and i <= self.r + self.l:
            i += 1
            # 计算展示的tab
            self.calcutab()

            # 显示或隐藏tab菜单
            self.tabMenuState()

            # 根据calcutab()展示tab
            self.updatetab()

            # 根据calcutab()隐藏tab至tabMenu
            self.updatetabMenu()

    def tabMenuState(self):

        self.btn_menu.setText('<<' + str(self.l + self.r))
        self.btn_menu.move(self.barWidth - self.tabbar.tabSizeHint(0).height() * 2 - 2, 0)
        self.btn_menu.resize(self.tabbar.tabSizeHint(0).height() * 2, self.tabbar.tabSizeHint(0).height())

        if self.btn_menu_state == 0 and self.l + self.r > 0:

            self.btn_menu_state = 1
            self.btn_menu.show()
            self.barWidth += self.tabbar.tabSizeHint(0).height() * 2
            print('添加菜单')

        elif self.btn_menu_state == 1 and self.l + self.r == 0:

            self.btn_menu_state = 0
            self.btn_menu.hide()
            self.barWidth -= self.tabbar.tabSizeHint(0).height() * 2
            print('移除菜单')

    # 计算需要展示的页面
    def calcutab(self):

        # 当tab宽度大于窗口宽度时
        if self.barWidth > mw.w:

            self.tab_index = self.currentIndex()

            # 当前页面的右边tab比左边多
            if (self.page - self.tab_index) >= self.tab_index:

                """ index = 0
                while self.tabs_show_status[len(self.tabs_show_status)-self.r-1+index] == 0  :
                    index += 1
                self.tabs_show_status[len(self.tabs_show_status)-self.r-1+index] = 0 """

                hide_tab = self.tabs_text.index(mw.tabs.tabText(self.page))
                self.tabs_show_status[hide_tab] = 0

                # 更新数据
                self.r += 1
                self.tab_Rwidth = self.tabbar.tabSizeHint(self.page).width()
                print('调用删右边')
                print(self.tabs_show_status)

            # 当前页面的右边tab比左边少
            else:

                """ index = 0
                while self.tabs_show_status[self.l-index] == 0 :
                    index += 1
                self.tabs_show_status[self.l-index] = 0 """

                hide_tab = self.tabs_text.index(mw.tabs.tabText(0))
                self.tabs_show_status[hide_tab] = 0

                # 更新数据
                self.l += 1

                print('调用删左边')
                print(self.tabs_show_status)

        # 当tab宽度小于窗口宽度时
        elif self.barWidth + 130 < mw.w and len(self.tabs_show_status) - self.r - self.l < len(self.tabs_show_status):
            self.tab_index = self.currentIndex()

            # 当前页面的右边tab比左边多
            if (self.page - self.tab_index) >= self.tab_index:

                if self.l > 0:

                    index = 0
                    while self.tabs_show_status[self.l - 1 + 1 - index] == 1 and self.l - 1 + 1 - index < len(
                            self.tabs_show_status) - 1:
                        index += 1
                    self.tabs_show_status[self.l - 1 + 1 - index] = 1

                    # 更新数据
                    self.l -= 1

                    print('调用1左添加')
                    print(self.tabs_show_status)

                elif self.l == 0:

                    index = 0
                    while self.tabs_show_status[len(self.tabs_page) - self.r - 1 + index] == 1 and len(
                            self.tabs_page) - self.r - 1 + index < len(self.tabs_show_status) - 1:
                        index += 1
                    self.tabs_show_status[len(self.tabs_page) - self.r - 1 + index] = 1

                    # 更新数据
                    self.r -= 1

                    print('调用1右添加')
                    print(self.tabs_show_status)

            # 当前页面的右边tab比左边少
            elif (self.page - self.tab_index) < self.tab_index:

                if self.r > 0:

                    index = 0
                    while self.tabs_show_status[len(self.tabs_page) - self.r - 1 + index] == 1 and len(
                            self.tabs_page) - self.r - 1 + index < len(self.tabs_page) - 1:
                        index += 1
                    self.tabs_show_status[len(self.tabs_page) - self.r - 1 + index] = 1

                    # 更新数据
                    self.r -= 1
                    print('调用2右添加')
                    print(self.tabs_show_status)

                elif self.r == 0:

                    index = 0
                    while self.tabs_show_status[self.l - 1 + 1 - index] == 1 and self.l - 1 + 1 - index < len(
                            self.tabs_show_status) - 1:
                        index += 1
                    self.tabs_show_status[self.l - 1 + 1 - index] = 1

                    # 更新数据
                    self.l -= 1

                    print('调用2左添加')
                    print(self.tabs_show_status)

    def updatetab(self):
        for i in range(0, (len(self.tabs_page))):

            # 需添加页面
            if self.indexOf(self.tabs_page[i]) == -1 and self.tabs_show_status[i] == 1:

                x = 0

                while self.indexOf(self.tabs_page[i + x]) == -1 and i + x < len(self.tabs_show_status) - 1:
                    x += 1

                if x > 0 and i + x != len(self.tabs_show_status) - 1:
                    self.insertTab(self.indexOf(self.tabs_page[i + x]), self.tabs_page[i], str(self.tabs_text[i]))

                else:
                    self.addTab(self.tabs_page[i], str(self.tabs_text[i]))

                # 更新数据
                self.barWidth += self.tabs_width[i]
                self.page += 1
                print('调用3')

            # 需隐藏页面
            if self.indexOf(self.tabs_page[i]) > -1 and self.tabs_show_status[i] == 0:
                self.removeTab(self.indexOf(self.tabs_page[i]))

                # 更新数据
                self.barWidth -= self.tabs_width[i]
                self.page -= 1

            self.tabMenuState()

    def updatetabMenu(self):

        for i in range(0, (len(self.tabs_page))):

            # 菜单需隐藏页面
            if self.tabs_show_status[i] == 1:
                self.tabs_menu_item[i].setVisible(False)

            # 菜单需显示页面
            if self.tabs_show_status[i] == 0:
                self.tabs_menu_item[i].setVisible(True)

    def menuJump(self, sri):

        print(self.tabs_show_status)

        # 所点tab右边
        if sri > self.l:
            self.tabs_show_status[sri] = 1

            hide_tab = self.tabs_text.index(mw.tabs.tabText(0))

            """ index=0
            while self.tabs_show_status[index] == 0 :
                index += 1 """
            self.tabs_show_status[hide_tab] = 0

            self.l += 1
            self.r -= 1

        elif sri < self.l:
            self.tabs_show_status[sri] = 1

            """ index=len(self.tabs_show_status)-1
            while self.tabs_show_status[index] == 0 :
                index -= 1 """

            hide_tab = self.tabs_text.index(mw.tabs.tabText(self.page))
            self.tabs_show_status[hide_tab] = 0

            self.l -= 1
            self.r += 1

        self.update()
        jump = self.indexOf(self.tabs_page[sri])
        # 跳转至新页面
        self.setCurrentIndex(jump)
        print('----------')
        print(sri)
        print('----------')

        """ #根据calcutab()展示tab
        self.updatetab()

        #根据calcutab()隐藏tab至tabMenu
        self.updatetabMenu() """
        print('调用跳转')
        print(self.tabs_show_status)


class TabBar(QTabBar):
    def __init__(self, parent, *args, **kwargs):
        QTabBar.__init__(self, parent, *args, **kwargs)
        # self.setTabsClosable(True)
        self.tabMoved.connect(self.tabMovedCode)
        self.btn_menu_state = 1
        qss = '''
        QTabBar::tab{
                    max-width:130;
                    min-width:50
                    }
        '''
        self.setStyleSheet(qss)

    def tabMovedCode(self, x, y, ):
        """ self.tabs_show_status = {}
        self.tabs_text = []
        self.tabs_page = {}
        self.tabs_width = {}
        self.tabs_menu_item = {} """
        """ print(move)
        print(moved) """
        print('--------------------------------')
        print(mw.tabs.tabs_show_status)
        print(mw.tabs.tabs_text)
        print(mw.tabs.tabs_page)
        print(mw.tabs.tabs_width)
        print(mw.tabs.tabs_menu_item)

        # 获取被移动的tab在本地数组的位置
        move = mw.tabs.tabs_text.index(mw.tabs.tabText(x))  # 选择的tab
        moved = mw.tabs.tabs_text.index(mw.tabs.tabText(y))  # 被移动的副tab

        # 修改其数据
        mw.tabs.tabs_show_status[999] = mw.tabs.tabs_show_status[move]
        mw.tabs.tabs_show_status[move] = mw.tabs.tabs_show_status[moved]
        mw.tabs.tabs_show_status[moved] = mw.tabs.tabs_show_status[999]
        del mw.tabs.tabs_show_status[999]

        char = mw.tabs.tabs_text[moved]
        mw.tabs.tabs_text[moved] = mw.tabs.tabs_text[move]
        mw.tabs.tabs_text[move] = char

        mw.tabs.tabs_page[999] = mw.tabs.tabs_page[move]
        mw.tabs.tabs_page[move] = mw.tabs.tabs_page[moved]
        mw.tabs.tabs_page[moved] = mw.tabs.tabs_page[999]
        del mw.tabs.tabs_page[999]

        mw.tabs.tabs_width[999] = mw.tabs.tabs_width[move]
        mw.tabs.tabs_width[move] = mw.tabs.tabs_width[moved]
        mw.tabs.tabs_width[moved] = mw.tabs.tabs_width[999]
        del mw.tabs.tabs_width[999]

        mw.tabs.tabs_menu_item[999] = mw.tabs.tabs_menu_item[move]
        mw.tabs.tabs_menu_item[move] = mw.tabs.tabs_menu_item[moved]
        mw.tabs.tabs_menu_item[moved] = mw.tabs.tabs_menu_item[999]

        """ mw.tabs.tabs_menu_item[move].triggered.connect(partial(mw.tabs.menuJump,move))
        mw.tabs.tabs_menu_item[moved].triggered.connect(partial(mw.tabs.menuJump,moved)) """

        del mw.tabs.tabs_menu_item[999]

        for i in range(0, len(mw.tabs.tabs_menu_item)):
            mw.tabs.tabs_menu_item[i].triggered.connect(partial(mw.tabs.menuJump, i))

        print(move)
        print(moved)

        print('--------------------------------')
        print(mw.tabs.tabs_show_status)
        print(mw.tabs.tabs_text)
        print(mw.tabs.tabs_page)
        print(mw.tabs.tabs_width)
        print(mw.tabs.tabs_menu_item)

    def btnMenu(self):
        self.btn_menu[0] = QPushButton(self)
        self.btn_menu.setText('菜单')
        self.btn_menu.resize(30, 30)
        # self.btn_menu.move(500, 500)
        print('菜单创建')


class MainWindow(QMainWindow):
    _instance = None

    def __new__(cls, *args, **kw):
        """ if cls._instance is None:
            cls._instance = QMainWindow.__new__(cls, *args, **kw)
        return cls._instance """

        if not hasattr(cls, 'mw'):
            orig = super(MainWindow, cls)
            cls.mw = orig.__new__(cls, *args, **kw)
        return cls.mw

    def __init__(self, parent=None, *args, **kwargs):
        QMainWindow.__init__(self, parent, *args, **kwargs)

        # 新
        self.x = str(0)

        AllWidget = QWidget()

        Alllayout = QVBoxLayout()
        # 设置控件无边界 无边框
        Alllayout.setSpacing(0)
        Alllayout.setContentsMargins(0, 0, 0, 0)
        AllWidget.setLayout(Alllayout)

        self.tabs = TabWidget()
        self.tabs.setMovable(True)
        self.tb = self.addToolBar("File")
        self.addtabs = QAction("添加页面", self)

        self.tb.addAction(self.addtabs)
        self.dialog = riLog()
        self.addtabs.triggered.connect(self.dialog.openDialog)

        for i in range(0, 10):
            self.x += str(i)
            self.tabs.addTabs(i, "Tab" + self.x)

        self.setCentralWidget(self.tabs)
        self.resize(2000, 1000)
        self.tabs.move(100, 100)
        """ self.btn = QPushButton(self)
        self.btn.move(0,0) """
        # Alllayout.addWidget(self.tabs.tabbar)
        Alllayout.addWidget(self.tabs)

        # Alllayout.addWidget(self.btn_menu)
        self.setCentralWidget(AllWidget)

    def resizeEvent(self, event):
        self.w = event.size().width()
        self.h = event.size().height()
        # print('刷新')

        self.tabs.update()

    def changeEvent(self, event):
        self.tabs.update()
        # print('最大化')
        print(self.w)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())